This addition gets the Finder’s selected files and folders. This works with all 7.x Finders (up to and including the scriptable Finder). Using it with any newer Finder could cause it to fail. Hopefully it won’t crash, but it probably won’t work. I check for any flavor of System 7, which means it could break on versions after 7.5.1, which works and it definately won’t work for System 8.
You can place script applications in the Apple Menu Items folder or with either OSA Menu or OtherMenu’s script menu and use the finder selection function to have your script operate on the selected files. Way cool.
Compared to the Scriptable Finder, which returns a list of object specifiers, this returns a list of aliases (or just one).
example:
finder selection
copyFile, deleteFile, moveFile & renameFile:
These commands work on files and lists of files. You can use file references (file "disk:folder:foo"), strings of pathnames or aliases to specify the files and folders for these commands. In contrast to the Scriptable Finder, these functions don’t put up dialogs, batch their operations and use temporary memory when needed.
RenameFile can only change the name of a file or folder. The source is a file or folder reference, alias or pathname and the destination is just the new name. It cannot be a new location.
DeleteFile is permanent and immediate. Be very careful with it. I recommend using “moveFile foo to (path to trash)” if you are at all worried or inclined toward cautiousness. This can delete empty folders. It also has an option “with unlocking” which allows it to delete locked files.
MoveFile only moves files or folders around on the disk they are on. It does not copy between disks. It cannot rename or replace files either. The destination is a folder, which you can specify either with a file reference, an alias or as a pathname string.
CopyFile uses temporary memory if available and tries to copy the file in 1 pass for maximum speed. The source may be either a file or a folder, or list of files and/or folders. The destination may be either a file or folder to copy to, unless the source is a folder in which case the destination must be a folder. The source folder will be copied into the destination folder. You cannot replace an existing folder so the replacing parameter is ignored when copying folders. You cannot rename a folder while copying it, so you’ll need to use renameFile after the copy completes.
If you try to replace a busy file, the copy will succeed but the busy file will be left in the temporary items folder and will appear in the Rescued Items folder in the trash after the next boot. It will then be safe to delete when you next empty the trash.
example:
copyFile "disk:folder:foo" to "disk2:folder:bar" with replacing
copyFile "disk:folder:foo" to "disk2:folder:bar" replacing yes
copyFile "disk:folder:foo" to "disk2:folder:bar" without replacing
copyFile "disk:folder:foo" to "disk2:folder:bar" replacing ask
deleteFile "disk:folder:foo"
deleteFile "disk:folder:foo" with unlocking
deleteFile file "disk:folder:"
moveFile "disk:folder:foo" to "disk:folder2:"
renameFile alias "disk:folder:foo" to "bar"
copyFile {"disk:folder:foo", alias "disk2:folder:bar:"} to "disk3:folder:"
This loads the FKEY resource and jumps to it. It does not press command-shift-N, so it will not trigger QuicKeys macros or any function which patches things to run at FKEY-like key combinations.
example:
execute FKEY "Switch-a-roo"
execute FKEY 5
keys pressed:
Keys Pressed returns the GetKey info in the form of a list of key names in string form.
example:
(keys pressed) contains "option"
(keys pressed) = {"option", "command"}
screen list:
“screen list” returns a list of screen info records which describe the monitors attached to the computer. You can specify which screen is first in the returned list by using the “starting with” parameter which takes either “main screen”, “deepest screen” or “largest screen”. The main screen is the one with the menu bar on it. It will always have 0,0 as its upper left coordinate. The deepest screen is the one with the most colors and closest to the main screen if there are more than one. The largest screen is the one with the most pixels. If no parameter is specified, the main screen is returned as the first item in the list.
The screen info record has these properties:
screen id integer -- The unique id of the screen.
screen size point -- The height and width of the screen.
bounds bounding rectangle -- The boundary rectangle for the screen.
color depth small integer -- The screen color depth setting in bits per pixel.
in color boolean -- If the screen is in color (versus grayscale).
has menu bar boolean -- If this is the main screen which the menu bar is on.
example:
screen list
number of items of (screen list)
bounds of item 1 of (screen list starting with largest screen)
set screens to:
The “set screens to” command takes a list of screen info records like you get from the “screen list” command. None of the fields are required, but several are highly recommended. Notably, the “screen id” and the “color depth” prevent any ambiguity, since the display manager will guess at these fields if they are not specified and could very well guess wrong if you have multiple monitors. It is much more likely to guess correctly on single monitor systems. It also has a tendancy to choose the most colors possible when you don’t specify a color depth when changing the screen size, so specifying a color depth is recommended.
Any changes made by this command are forgotten when the system restarts, unless you are running Display Manager 2 or greater. This can be had by installing the Display Enabler or running a system newer than 7.5.1. You may also need to throw away the “Display Preferences” file from your Preferences folder if your system will not remember the display settings across restarts.
Here is a handy script which works well from OSA Menu. What it does is save an applet which will set the screen to the state it was when the applet was created and move the icons to the positions they had then too. Basically, the way you use it, you set up your screen for 832x624 and run this script. Then you set it up for 1024x768 (or whatever) and run it again. From that point on, you only need to run the applets to get back and forth. The applets are required because when running the “set screens to” command from OSA Menu in the Finder, the Finder doesn’t get any time to update it’s understanding of the screen size and thus disallows the icon repositioning. Running it as an applet allows an idle event to get to the Finder and allow it to update. The applet then uses OSA Menu’s handler to run the icon repositioning script in the Finder’s layer for maximum speed and no updates.
First off, you’ll need to have an applet saved for the first script, since it copies this applet and replaces the script in it using “store script”. This is kind of tricky, but worth the bother. Take this script, change the alias to point at anything, compile and save it, then change the alias to point at the applet itself. Now you can run it and it will put a copy of the handler on the clipboard or you can just copy the handler out of it.
on SaveAsApplet(theScript, theFile)
copyFile alias "TRex:AppleScript™ Utilities:Scripts:SaveAs Applet" to file theFile replacing yes
store script theScript in theFile replacing yes
end SaveAsApplet
on run
set the clipboard to "on SaveAsApplet(theScript, theFile)
copyFile alias \"" & (path to me as string) & "\" to file theFile replacing yes
store script theScript in theFile replacing yes
end
"
end run
Now, we need the script which creates the applet. This one goes in OSA Menu.
script iconRestore
property iconNames : {}
property iconPositions : {}
on run
set cursor to watch cursor -- Jon's Commands
-- set the icons to their proper places
repeat with i from 1 to number of items of iconNames
set n to item i of iconNames
set p to item i of iconPositions
try
tell application "Finder"
set position of item n of desktop to p
end tell
on error
end try
end repeat
end run
end script
script screenRestore
property screenState : {}
property restoreScript : ""
on saveState()
set cursor to watch cursor -- Jon's Commands
copy (screen list) to screenState
tell application "Finder"
set iconList to every item of desktop
copy {} to iconRestore's iconNames
copy {} to iconRestore's iconPositions
repeat with i in iconList
copy name of i to end of iconRestore's iconNames
copy position of i to end of iconRestore's iconPositions
end repeat
end tell
set restoreScript to iconRestore
end saveState
on run
if (keys pressed) contains "Option" then
display dialog "Update to this configuration?" buttons {"Cancel", "OK"} default button "OK" with icon caution
saveState()
else
-- change the screens
set screens to screenState
-- create the file and tell OSA Menu to run it
set f to (path to temporary items folder as string) & "Temp " & ((the ticks) as string)
-- you need to set this alias to point at any applet
copyFile alias "TRex:AppleScript™ Utilities:Scripts:SaveAs Applet" to file theFile replacing replaceMode
store script theScript in file theFile replacing replaceMode
end SaveAsApplet
on run
tell screenRestore to saveState()
-- Figure out the name based on the main screen size
set rez to screen size of item 1 of (screenRestore's screenState)
set screenName to (item 1 of rez as string) & " x " & (item 2 of rez as string)
try
-- Set the save as directory, which may not work under 7.5
set defPath to path to desktop as string
SetCurrentDir defPath -- Donald's Commands
on error number -1708 -- event not handled, SetCurrentDir not installed
end try
-- Find out where to save
set theFile to new file with prompt "Save desktop configuration as:" default name screenName
set theFile to theFile as string
SaveAsApplet(screenRestore, theFile, yes)
end run
Here’s another script which simply toggles the screen size of the main display:
set s to item 1 of (screen list)
set si to screen id of s
if screen size of s = {832, 624} then
set screens to {screen id:si, screen size:{1024, 768}, color depth:16}
else
set screens to {screen id:si, screen size:{832, 624}, color depth:16}
end if
example:
set screens to {color depth:256}
set screens to {{screen id:256, screen size:{1024, 768}, color depth:256}, {screen id:257, color depth:4, in color:false}}
machine environment:
Machine Environment returns a keyworded record object of common machine information from Gestalt. You can also feed it a Gestalt selector and it will return the long word response. This provides complete access to all of the Gestalt functions that exist. You can use the “check bit” parameter to return a boolean which tells if that bit is on. Bits are numbered from 1 to 32 with number 1 being the lowest or rightmost bit. In this way you can get any information from Gestalt.
The environment info record provides these properties:
machine type string -- The name of the Macintosh model (less specific in recent systems).
CPU type string -- The CPU installed.
System version string -- The current System version.
FPU boolean -- Does this machine have an FPU?
Color Quickdraw boolean -- Does this machine have color Quickdraw?
AppleTalk version extended real -- The current AppleTalk version.
keyboard string -- The name of the main keyboard.
Data Access Manager boolean -- Does this machine have the Data Access Manager installed?
software power off boolean -- Does this machine turn off when shutdown?
logical RAM integer -- Amount of RAM available to the system.
physical RAM integer -- Amount of RAM installed in this machine.
active scripts integer -- Number of script systems active.
virtual memory boolean -- Is virtual memory on?
scriptable Finder boolean -- Is the scriptable Finder present?
owner name string -- The owner name in sharing setup.
sharing name string -- The machine name in sharing setup.
PowerPC boolean -- Whether this machine is a PowerPC.
Both this and “keys pressed” use STR# resources if you are inclined to localize them. The machine info is a subset of the available Gestalt selectors. If you have need of others, let me know and I might include them in a future version, although you can get raw information for any gestalt selector directly.
example:
machine environment
scriptable Finder of (machine environment)
machine environment "code"
machine environment "code" check bit 0
clipboard info, the clipboard & set the clipboard to:
All of these can manage multiple data types. Styled text is the default data type, with plain text (known as string) as the backup. International text is also supported, as are a lot of other data formats. Almost any resource type can be manipulated in AppleScript as an AEDesc in applications. Pictures and sounds are also popular to move around.
There is a problem with using the clipboard in multiple programs. That is, you can only use these commands in the front application. The simplest thing to do is use “activate” first to get the application to the front and then nab or grab the clipboard. Some applications don’t seem to check if the scrap has changed while they are running since it only changes when you switch layers in System 7. In this case you can simply activate an app and then activate the original.
Here’s a routine to change the clipboard:
on slamClipboard(theText)
tell application "Finder"
if not frontmost then
set oldApp to every process whose frontmost = true
activate
set the clipboard to theText
activate oldApp
else
set the clipboard to theText
end if
end tell
end slamClipboard
Here’s a routine to send your clipboard to another machine. It uses “login as” and “logout” from the GTQ 1.2 Library.
set cookie to login as "Clippy" password "Clippy"
try
set theText to the clipboard
tell application "Finder" of machine "Office in a Box"
if not frontmost then
set oldApp to path to frontmost application
activate
set the clipboard to theText
open oldApp
else
set the clipboard to theText
end if
end tell
logout cookie
on error m number n
logout cookie
error m number n
end try
Here’s the same script in reverse. This one gets the clipboard from another machine.
set cursor to watch cursor
set cookie to login as "Clippy" password "Clippy"
tell application "Finder" of machine "Office in a Box"
activate
set theText to the clipboard
end tell
tell application "Finder"
if not frontmost then
set oldApp to path to frontmost application
activate
set the clipboard to theText
open oldApp
else
set the clipboard to theText
end if
end tell
logout cookie
set cursor to arrow cursor
example:
clipboard info
set foo to the clipboard
set foo to the clipboard as "PICT"
set the clipboard to foo
sound volume & set sound volume to:
Both of these use a number between 0 and 7 for the volume, just like everyone else.
example:
set oldVol to sound volume
set sound volume to 5
set sound volume to oldVol
play sound:
This can play sound (‘snd ’) resources installed in the system or the current open files by either name or id number. It can also play sound resources out of files and out of AppleScript variables (typically accessed via the clipboard). You cannot interrupt a sound in progress in this version and the sounds are played synchronously. This command is a small improvement on Donald’s sample code from the Language Reference Manual.
example:
play sound "I’m sorry Dave..."
run script resource:
This matches the AppleScript Run Script command but works on resources instead of files. This allows you to bundle several scripts (typically from other OSA components such as QuicKeys) into a single script file or application. I’ve used it to place the ‘scpt’ resources from QuicKeys scripts into an applet and run them from there.
There is a problem with having more than 1 ‘scpt’ resource per file and that is the Script Editor. It finds the script to display by using Get1IndResource('scpt', 1) which can return the wrong resource if you have several. If you are literate with ResEdit you can make sure the proper script resource is last in the file, but that’s less certain than the other technique I recommend, which is to change the script resource’s type to ‘Scpt’ which is not recognized by the Script Editor. You need to copy the script resource as hex data and paste it into a new empty ‘Scpt’ resource. This way allows no conflicts. Another solution is to use my ScriptServer application (available on Info-Mac & gaea) which allows you to create script resources of any type and id. This makes it simple to create a script application which combines AppleScript and QuicKeys scripts. You can even record a QuicKeys script, decompile it with ScriptServer, edit it and recompile it as a piece of a script application.
Yet another option is simply to record a QuicKeys script, copy it and paste the text into your AppleScript script with the “run script foo in QuicKeys” command with foo as your text or a variable with text in it. This works well with simple scripts and doesn’t require this osax. Unfortunately, the Run Script 1.1 osax has a memory leak when doing this. Running a compiled script resource is marginally faster too.
You can reference script resources by name or number.
example:
run script resource "Flail madly"
free memory:
This returns the current value of the function FreeMem. It shows the amount of free memory available in the current application’s current heap. Useful for finding memory leaks. You can also specify which heap you would like info about with the constants appZone and sysZone.
example:
free memory
free memory sysZone
the ticks:
This returns the current value of TickCount. This is useful for timing functions from scripts. Unfortunately, this opens the resource file for Jon’s Commands every time and thus affects your timing slightly, making it more useful for large timings where the overhead is less instead of small ones. The example is a script object which can record a series of times using the ticks. Include it at the beginning of your script and call it’s methods.
example:
script SmartTimer
property IMrunning : false
property startTime : 0
property endTime : 0
property timeLog : {}
on startTimer()
if IMrunning then
error "Timer already running"
end if
try
set startTime to the ticks
set IMrunning to true
on error theMsg number -1708
error "You need Jon’s Commands installed to use this script object."
end try
end startTimer
on stopTimer()
if not IMrunning then
error "Timer is not running"
end if
set endTime to the ticks
set IMrunning to false
set elapsedTime to endTime - startTime
set timeLog to timeLog & {elapsedTime}
return elapsedTime
end stopTimer
on averageTime()
set sum to 0
set n to number of items of timeLog
repeat with i in timeLog
set sum to sum + i
end repeat
return sum / n
end averageTime
on getLog()
return timeLog
end getLog
on clearLog()
set timeLog to {}
end clearLog
end script
walk folders:
This makes file processors very simple and fast. It takes a list of files and folders and a script. It then walks through them all and sends each file to an open handler in the script. Note that as of version 1.3.4, walk folders steps backwards through directories (reverse alphabetical order) so that you can delete files without affecting the subsequent indexing. It is possible to make this be an option if people whine enough.
The “only using files of type” parameter allows you to specify one or more file types that will be operated on. Only files of the types specified will be sent to your script parameter. The types are 4 character strings with the obscure codes you will have to find out about. Normal choices are things like "APPL", "osax" and "TEXT".
In addition, there are 2 boolean parameters, “using files” and “using folders”. “using files” defaults to true and causes all files to be run through the script. “using folders” defaults to false and causes all folders to be run through the script. You can set them to true or false by using “with using folders” and/or “without using files”.
example:
on open (theFiles)
script foo
on open (theFile)
display dialog theFile as string
end open
end script
walk folders theFiles with script foo only using files of type {"TEXT", "osas"}
end open
set cursor to:
This allows you to change the current cursor to indicate a busy script. It is problematic since the front application can change it right back, and many do, but it can be very useful nonetheless.
You can use the five standard cursors; arrow cursor, watch cursor, I beam cursor, cross cursor & plus cursor, plus a busy cursor which spins. You can also specify the name or number of a CURS resource or, using the “with cursor list” parameter, an acur resource. Subsequent calls with the “busy cursor” will increment this cursor one step.
The busy cursor keeps an acur and all the CURS resources in memory between calls. The “with cursor list” parameter is only necessary on the first call and will reinitialize the cursor if always supplied (i.e. the cursor will not spin). You can clear this memory by setting the cursor to something other than a busy cursor (i.e. watch cursor or arrow cursor).
These are the busy cursors available in Jon’s Commands, use their names or numbers (names are probably less likely to conflict with other resources):
This does not support color cursors yet.
example:
set cursor to busy cursor with cursor list "Zen Cursor"
repeat
set cursor to busy cursor
end repeat
set cursor to watch cursor
AE user interaction level:
This allows you to get and set the AppleEvent manager’s user interaction level. This way you can allow interaction from remote machines or disallow interaction from local scripts. In order for this to work, the program which is doing the interaction must explicitly check if interaction is allowed. Hopefully all scriptable applications do.
This returns the current state and then optionally sets it to the new state.
The only drawback with this command is that you cannot turn off user interaction in the current application from a script run by OSA Menu. Since the lowest level is “AE interact with self” and a script running by OSA Menu is sending events to the same application, this is always allowed so they think thy can put up dialogs. Applications need to support a “never interact” mode explicitly. Apple’s PhotoFlash does. (shameless plug from one of the authors)
example:
set oldLevel to AE user interaction level AE interact with self
AE user interaction level oldLevel
choose color:
This function displays the standard color picker and returns an RGB color value. You can specify the prompt and the initial color. RGB colors can be specified via a list of three numbers between 0 and 65535. It’s actually a 3 word data value which can be coerced to and from a list.
example:
choose color
set newColor to choose color "Pick your favorite color:" starting color {0, 0, 0}
example script:
-- paste an HTML color reference into BBEdit
property lastColor : {35000, 35000, 35000}
set lastColor to choose color "Choose a background color:" starting color lastColor
set s to "#"
set a to "0123456789ABCDEF"
repeat with i in lastColor
set q to round (i / 65535 * 256)
set h to q div 16
set l to q mod 16
set s to s & character (h + 1) of a & character (l + 1) of a
end repeat
tell application "BBEdit 3.5"
set selected text of window 1 to s
end tell
keyboard lights:
This function returns the current setting of the keyboard lights on an ADB extended keyboard and sets them to whatever you specify, which allows you to do a progress indicator which is not obscured by screen savers. Note that this command can override the setting of the caps lock light so that it may not match the actual keyboard setting. Pressing the caps lock key a few times will reset it.
The input and return values can be a list of enums or a number. The list has three possible enums in it, num lock light (1), caps lock light (2), and scroll lock light (4). You can use either the enums or an integer combination of the values in parentheses (from 0 to 7). You can also use any other number to signify no change to the lights but that you want the return value to be an integer.
example:
keyboard lights {num lock light, caps lock light, scroll lock light} -- turn the lights on & return a list
set oldLights to keyboard lights {} -- turn the lights off & return a list
set oldLights to keyboard lights -1 -- no change but returns an integer
example script:
repeat
repeat with i from 0 to 7
keyboard lights i
repeat 10000 times
end repeat
if (keys pressed) ≠ {} then
keyboard lights 0
error number -128
end if
end repeat
end repeat
snag object:
This command is a geeky developer tool mostly of use to people writing applications which want to send a single object specifier to another scriptable application, like the Finder, but don’t want to either build the object specifier by hand or load AppleScript for this simple task (typically because of the memory requirements). This command allows them to write the object specfier in their script editor like normal and then, using the “snag object” command, save that object specifier to a file. They can then paste this object specifier resource into their application and build a simple GetData event with it as the direct parameter. The results are returned in the reply and everyone’s cruising.
example:
snag object <reference> in <file> id <number> type <string>
example script:
set f to path to desktop as string
tell application "Finder"
snag object (creator type of processes whose visible = false) in file (f & "Test") id 128 type "obj "
end tell
Coercions:
string to file specification
styled text to file specification
international text to file specification
These coercions allow you to use strings where a program or osax expects a file specification. Note that the AppleScript class “file” is really an object reference, not simply an FSSpec, although it can be coerced to one. You can create an FSSpec by using this command: “set x to "disk:folder:file" as «class fss »”. They are particularly easy to implement. With these coercions you don’t need to worry about them though.